home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume9 / compress.ms < prev    next >
Encoding:
Text File  |  1989-11-16  |  36.9 KB  |  1,353 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v09i005: 16 bit compress for MSDOS
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: graham@tsmith.UUCP
  5.  
  6. Posting-number: Volume 9, Issue 5
  7. Submitted-by: graham@tsmith.UUCP
  8. Archive-name: compress.ms
  9.  
  10.     Recently, there have been people looking for source for compress.c to run
  11. under MSDOS. Here is one that may fit the bill.
  12.  
  13. Doug.
  14.  
  15. ------------------------------ Cut Here ------------------------------------
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  21. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  22. # If this archive is complete, you will see the following message at the end:
  23. #        "End of shell archive."
  24. # Contents:  README makefile compress.c
  25. # Wrapped by graham@tsmith on Wed Nov 15 20:52:00 1989
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'README' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'README'\"
  29. else
  30. echo shar: Extracting \"'README'\" \(609 characters\)
  31. sed "s/^X//" >'README' <<'END_OF_FILE'
  32. XHere is a version of compress 4.0 hacked for MSDOS. A makefile is provided
  33. Xwhich will compile it using Microsoft C, Turbo C, or Zortech C. The makefile
  34. Xwill need editing if other than the Microsoft compiler is used.
  35. XThe program requires about 400K to run. It takes the same command line
  36. Xargs as does the UNIX program of the same name, and should be compatible
  37. Xin all ways with that program. It will decode a 16 bit compressed file,
  38. Xand can generate the same. On my machine, it decodes about twice as quickly
  39. Xas the "u16" decompress program posted earlier to c.s.m.
  40. X
  41. XDoug Graham.
  42. Xuunet!mitel!sce!tsmith!graham
  43. END_OF_FILE
  44. if test 609 -ne `wc -c <'README'`; then
  45.     echo shar: \"'README'\" unpacked with wrong size!
  46. fi
  47. # end of 'README'
  48. fi
  49. if test -f 'makefile' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'makefile'\"
  51. else
  52. echo shar: Extracting \"'makefile'\" \(1083 characters\)
  53. sed "s/^X//" >'makefile' <<'END_OF_FILE'
  54. X#
  55. X# Makefile for compress.
  56. X#
  57. X# If memory usage is a problem under DOS, you may want to do a
  58. X#
  59. X#    "exemod compress.exe /MAX 0"
  60. X#
  61. X# in order to reduce the size of the near heap. If this is done on the
  62. X# Microsoft executable, memory requirements drop to about 380K from 410K
  63. X# Depending on how the other compilers manage their near/far heaps, this
  64. X# should have similar results there as well.
  65. X#
  66. X
  67. XDOSDEFS =  -Di8088 -DMSDOS -DPROTO
  68. X
  69. X#
  70. X# Microsoft C 5.0 under MSDOS
  71. X#
  72. X# The resulting executable is faster by about 20% than either Turbo C,
  73. X# or Zortech C.
  74. X#
  75. Xcompress.exe: compress.c
  76. X    cl -o compress.exe -W3 -Ox -DMSC $(DOSDEFS) compress.c
  77. X
  78. X#
  79. X# Turbo C 2.0 under MSDOS
  80. X#
  81. X# compress.exe: compress.c
  82. X#     tcc -ecompress.exe -Z -O -G -w $(DOSDEFS) compress.c
  83. X
  84. X#
  85. X# Zortech C under MSDOS
  86. X#
  87. X# compress.exe: compress.c
  88. X#     ztc -ocompress.exe -o $(DOSDEFS) compress.c
  89. X
  90. X#
  91. X# Sun OS 3.5.
  92. X# Compression is slightly slower than /usr/ucb/compress probably
  93. X# because the compiler is doing lots of "extl"'s. Decompression
  94. X# is slightly faster.
  95. X#
  96. X# compress:    compress.c
  97. X#     cc -O -DBSD4_2 -o compress compress.c
  98. END_OF_FILE
  99. if test 1083 -ne `wc -c <'makefile'`; then
  100.     echo shar: \"'makefile'\" unpacked with wrong size!
  101. fi
  102. # end of 'makefile'
  103. fi
  104. if test -f 'compress.c' -a "${1}" != "-c" ; then 
  105.   echo shar: Will not clobber existing file \"'compress.c'\"
  106. else
  107. echo shar: Extracting \"'compress.c'\" \(32700 characters\)
  108. sed "s/^X//" >'compress.c' <<'END_OF_FILE'
  109. X/* 
  110. X * Compress - data compression program 
  111. X */
  112. Xstatic char rcs_ident[] = "@(#) compress,v 4.1 (DOS) 89/11/10 02:43:00 doug Release $";
  113. X
  114. X/*
  115. X * compress.c - File compression ala IEEE Computer, June 1984.
  116. X *
  117. X * Authors:    Spencer W. Thomas    (decvax!harpo!utah-cs!utah-gr!thomas)
  118. X *        Jim McKie        (decvax!mcvax!jim)
  119. X *        Steve Davies        (decvax!vax135!petsd!peora!srd)
  120. X *        Ken Turkowski        (decvax!decwrl!turtlevax!ken)
  121. X *        James A. Woods        (decvax!ihnp4!ames!jaw)
  122. X *        Joe Orost        (decvax!vax135!petsd!joe)
  123. X *        Doug Graham        (uunet!mitel!sce!tsmith!graham)
  124. X *
  125. X * Revision 4.1 (DOS) 89/11/10 02:43:00 doug
  126. X * Ported to MSDOS. Still works elsewhere, but maybe not as quickly.
  127. X * Removed as much long arithmetic as possible for speed on 16 bit machines.
  128. X * Use unsigned short's instead. Changed secondary hashing function to limit
  129. X * hash table size to 64K. This means table indexes can be 16 bit shorts.
  130. X * This compress will not generate codes from MAXMAXCODE (0xf000) thru
  131. X * 0xffff. Doesn't appear to hurt compression much. Removed speed hacks for
  132. X * other machines so I could understand the code. Added some for the i8088.
  133. X * Send CLEAR immediately when hash table fills instead of waiting for the
  134. X * compression ratio to drop. This is faster, and in some cases improves
  135. X * compression (but more often reduces it slightly). Junked the variable
  136. X * size hash table stuff because I am depending on 16 bit unsigned integer
  137. X * wrap around for indexing into hash table, so the table must have 2^16
  138. X * entries. Took out the XENIX_16 stuff. The DOS way ought to work on Xenix
  139. X * as well, and should be faster, but I don't have access to Xenix in order
  140. X * to find out. Added some extra error checking on decompression to try to
  141. X * avoid blowing the machine out of the water when decompressing a corrupt
  142. X * file. Add "okunlink" to avoid the problem of losing the output file as
  143. X * well as the input file if ^C is hit at the wrong time. Lot's of other
  144. X * cosmetic changes.
  145. X *
  146. X * Revision 4.0  85/07/30  12:50:00  joe
  147. X * Removed ferror() calls in output routine on every output except first.
  148. X * Prepared for release to the world.
  149. X * 
  150. X * Revision 3.6  85/07/04  01:22:21  joe
  151. X * Remove much wasted storage by overlaying hash table with the tables
  152. X * used by decompress: tab_suffix[1<<BITS], stack[8000].  Updated USERMEM
  153. X * computations.  Fixed dump_tab() DEBUG routine.
  154. X *
  155. X * Revision 3.5  85/06/30  20:47:21  jaw
  156. X * Change hash function to use exclusive-or.  Rip out hash cache.  These
  157. X * speedups render the megamemory version defunct, for now.  Make decoder
  158. X * stack global.  Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
  159. X *
  160. X * Revision 3.4  85/06/27  12:00:00  ken
  161. X * Get rid of all floating-point calculations by doing all compression ratio
  162. X * calculations in fixed point.
  163. X *
  164. X * Revision 3.3  85/06/24  21:53:24  joe
  165. X * Incorporate portability suggestion for M_XENIX.  Got rid of text on #else
  166. X * and #endif lines.  Cleaned up #ifdefs for vax and interdata.
  167. X *
  168. X * Revision 3.2  85/06/06  21:53:24  jaw
  169. X * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
  170. X * Default to "quiet" output (no compression statistics).
  171. X *
  172. X * Revision 3.1  85/05/12  18:56:13  jaw
  173. X * Integrate decompress() stack speedups (from early pointer mods by McKie).
  174. X * Repair multi-file USERMEM gaffe.  Unify 'force' flags to mimic semantics
  175. X * of SVR2 'pack'.  Streamline block-compress table clear logic.  Increase 
  176. X * output byte count by magic number size.
  177. X * 
  178. X * Revision 3.0   84/11/27  11:50:00  petsd!joe
  179. X * Set HSIZE depending on BITS.  Set BITS depending on USERMEM.  Unrolled
  180. X * loops in clear routines.  Added "-C" flag for 2.0 compatibility.  Used
  181. X * unsigned compares on Perkin-Elmer.  Fixed foreground check.
  182. X *
  183. X * Revision 2.7   84/11/16  19:35:39  ames!jaw
  184. X * Cache common hash codes based on input statistics; this improves
  185. X * performance for low-density raster images.  Pass on #ifdef bundle
  186. X * from Turkowski.
  187. X *
  188. X * Revision 2.6   84/11/05  19:18:21  ames!jaw
  189. X * Vary size of hash tables to reduce time for small files.
  190. X * Tune PDP-11 hash function.
  191. X *
  192. X * Revision 2.5   84/10/30  20:15:14  ames!jaw
  193. X * Junk chaining; replace with the simpler (and, on the VAX, faster)
  194. X * double hashing, discussed within.  Make block compression standard.
  195. X *
  196. X * Revision 2.4   84/10/16  11:11:11  ames!jaw
  197. X * Introduce adaptive reset for block compression, to boost the rate
  198. X * another several percent.  (See mailing list notes.)
  199. X *
  200. X * Revision 2.3   84/09/22  22:00:00  petsd!joe
  201. X * Implemented "-B" block compress.  Implemented REVERSE sorting of tab_next.
  202. X * Bug fix for last bits.  Changed fwrite to putchar loop everywhere.
  203. X *
  204. X * Revision 2.2   84/09/18  14:12:21  ames!jaw
  205. X * Fold in news changes, small machine typedef from thomas,
  206. X * #ifdef interdata from joe.
  207. X *
  208. X * Revision 2.1   84/09/10  12:34:56  ames!jaw
  209. X * Configured fast table lookup for 32-bit machines.
  210. X * This cuts user time in half for b <= FBITS, and is useful for news batching
  211. X * from VAX to PDP sites.  Also sped up decompress() [fwrite->putc] and
  212. X * added signal catcher [plus beef in writeerr()] to delete effluvia.
  213. X *
  214. X * Revision 2.0   84/08/28  22:00:00  petsd!joe
  215. X * Add check for foreground before prompting user.  Insert maxbits into
  216. X * compressed file.  Force file being uncompressed to end with ".Z".
  217. X * Added "-c" flag and "zcat".  Prepared for release.
  218. X *
  219. X * Revision 1.10  84/08/24  18:28:00  turtlevax!ken
  220. X * Will only compress regular files (no directories), added a magic number
  221. X * header (plus an undocumented -n flag to handle old files without headers),
  222. X * added -f flag to force overwriting of possibly existing destination file,
  223. X * otherwise the user is prompted for a response.  Will tack on a .Z to a
  224. X * filename if it doesn't have one when decompressing.  Will only replace
  225. X * file if it was compressed.
  226. X *
  227. X * Revision 1.9  84/08/16  17:28:00  turtlevax!ken
  228. X * Removed scanargs(), getopt(), added .Z extension and unlimited number of
  229. X * filenames to compress.  Flags may be clustered (-Ddvb12) or separated
  230. X * (-D -d -v -b 12), or combination thereof.  Modes and other status is
  231. X * copied with copystat().  -O bug for 4.2 seems to have disappeared with
  232. X * 1.8.
  233. X *
  234. X * Revision 1.8  84/08/09  23:15:00  joe
  235. X * Made it compatible with vax version, installed jim's fixes/enhancements
  236. X *
  237. X * Revision 1.6  84/08/01  22:08:00  joe
  238. X * Sped up algorithm significantly by sorting the compress chain.
  239. X *
  240. X * Revision 1.5  84/07/13  13:11:00  srd
  241. X * Added C version of vax asm routines.  Changed structure to arrays to
  242. X * save much memory.  Do unsigned compares where possible (faster on
  243. X * Perkin-Elmer)
  244. X *
  245. X * Revision 1.4  84/07/05  03:11:11  thomas
  246. X * Clean up the code a little and lint it.  (Lint complains about all
  247. X * the regs used in the asm, but I'm not going to "fix" this.)
  248. X *
  249. X * Revision 1.3  84/07/05  02:06:54  thomas
  250. X * Minor fixes.
  251. X *
  252. X * Revision 1.2  84/07/05  00:27:27  thomas
  253. X * Add variable bit length output.
  254. X *
  255. X */
  256. X
  257. X#include <stdio.h>
  258. X#include <ctype.h>
  259. X#include <signal.h>
  260. X#include <sys/types.h>
  261. X#include <sys/stat.h>
  262. X#ifndef __ZTC__
  263. X#include <malloc.h>
  264. X#endif
  265. X#ifndef BSD4_2
  266. X#include <stdlib.h>
  267. X#include <io.h>
  268. X#endif
  269. X#include <string.h>
  270. X#include <fcntl.h>
  271. X#ifdef MSDOS
  272. X#include <dos.h>
  273. X#endif
  274. X
  275. X#ifdef PROTO
  276. X/*
  277. X * Zortech appears to be missing this prototype, and MSC uses some
  278. X * silly structure as the second arg. Turbo C doesn't support this
  279. X * call at all.
  280. X */
  281. Xextern int utime(char *path, time_t times[]);
  282. X#endif
  283. X
  284. X#define BITS        16        /* max number of bits/code */
  285. X#define INIT_BITS    9        /* initial number of bits/code */
  286. X
  287. X#define MAXCODE(n_bits)        ((code_t)((1L << (n_bits)) - 1))
  288. X
  289. X/*
  290. X * Magic numbers which should appear at the beginning of a compressed file.
  291. X */
  292. X#define MAGIC0    0x1f
  293. X#define MAGIC1    0x9d
  294. X
  295. X/*
  296. X * Defines for third byte of header
  297. X */
  298. X#define BIT_MASK    0x1f
  299. X#define BLOCK_MASK    0x80
  300. X
  301. X#if 0
  302. X#define CHECK_GAP    10000        /* ratio check interval */
  303. X#endif
  304. X
  305. X/*
  306. X * the next two codes should not be changed lightly, as they must not
  307. X * lie within the contiguous general code space.
  308. X */ 
  309. X#define FIRST    257        /* first free entry */
  310. X#define    CLEAR    256        /* table clear output code */
  311. X
  312. X#define DE_STACKLEN    8192    /* Size of decoder stack */
  313. X
  314. X#define HSIZE    (1L << 16)    /* Size of the hash table. Don't change this */
  315. X
  316. Xtypedef unsigned char    uchar;
  317. Xtypedef unsigned long    ulong;
  318. Xtypedef unsigned short    code_t;
  319. Xtypedef    unsigned short    hash_t;
  320. X
  321. X#ifdef PROTO
  322. X#define ARGS(x)    x
  323. X#else
  324. X#define ARGS(x)    ()
  325. X#endif
  326. X
  327. Xvoid        main ARGS((int argc, char **argv));
  328. Xvoid        Usage ARGS((void));
  329. Xvoid        version ARGS((void));
  330. Xvoid        compress ARGS((void));
  331. Xvoid        decompress ARGS((void));
  332. Xvoid        copystat ARGS((void));
  333. Xvoid        writeerr ARGS((void));
  334. Xvoid        cl_hash ARGS((void));
  335. Xvoid        putcode ARGS((code_t code));
  336. Xvoid        prratio ARGS((long num, long den));
  337. Xint        ofopen ARGS((char *filename));
  338. Xint        ifopen ARGS((char *filename));
  339. Xint        check_magic ARGS((void));
  340. Xint        need_clear ARGS((void));
  341. Xvoid        onintr ARGS(());
  342. Xvoid        oops ARGS(());
  343. Xint        taballoc ARGS((void));
  344. Xvoid        clearhash ARGS((void));
  345. X
  346. X/*
  347. X * block compression parameters -- after all codes are used up,
  348. X * and compression rate changes, start over.
  349. X */
  350. Xint        block_compress = BLOCK_MASK;
  351. X
  352. Xint        maxbits = BITS;        /* user settable max # bits/code */
  353. Xint        magic = 1;        /* 3-byte magic number header */
  354. Xint        zcat_flg = 0;        /* Output on stdout */
  355. Xint        verbose = 0;        /* don't tell me about compression */
  356. Xint        force = 0;        /* Force overwrite of output file */
  357. Xint        do_decomp = 0;        /* Decompress rather than compress. */
  358. Xchar        ofname[100];        /* Output file name */
  359. Xint        foreground;        /* Running in foreground? */
  360. Xint        exit_stat = 0;        /* Exit status */
  361. Xuchar        bitbuf[BITS+2];        /* For (dis)assembling code bytes */
  362. Xint        okunlink;        /* OK for sig handler to unlink output file */
  363. Xchar        *ifname;
  364. X
  365. X#ifdef i8088
  366. X
  367. Xuchar        *de_stack;
  368. Xuchar far    *charptr1;
  369. Xuchar far    *codeptrs1[2];
  370. Xuchar far    *codeptrs2[2];
  371. X
  372. X#define de_suffixof(i)    charptr1[i]
  373. X#define de_prefixof(i)    (*(code_t far *)&codeptrs1[i&1][i&~1])
  374. X
  375. X#define en_hashchar(i)    charptr1[i]
  376. X#define en_hashent(i)    (*(code_t far *)&codeptrs1[i&1][i&~1])
  377. X#define en_hashcode(i)    (*(code_t far *)&codeptrs2[i&1][i&~1])
  378. X
  379. X#ifndef MK_FP
  380. X#define MK_FP(seg, ofs) \
  381. X    ((void far *)(((ulong)(seg) << 16) | (unsigned)(ofs)))
  382. X#endif
  383. X
  384. X#define    PARA    16        /* Size of a paragraph */
  385. X
  386. X/*
  387. X * Return a segment address which is the segment part of the normalized
  388. X * version of "fp" rounded upwards.
  389. X * I use this on the far pointers returned by "farmalloc". While
  390. X * they are probably already normalized, I have never seen this
  391. X * stated anywhere in the doc's.
  392. X *
  393. X * There is a lot of junk below which would be unecessary if only
  394. X * there were a reasonably compiler independent way of allocating
  395. X * a given number of PARAGRAPHS (like TC's allocmem). I can't find
  396. X * one though.
  397. X */
  398. X#define FP_SEGCEIL(fp) \
  399. X    (FP_SEG(fp) + (FP_OFF(fp) + PARA - 1)/PARA)
  400. X
  401. X/*
  402. X * Allocate space for the tables used in {en,de}coding. These tables
  403. X * reside in the far heap. It may seem inefficient to be using far pointers
  404. X * for the base of these tables, because the offset portion will always be zero.
  405. X * We could just keep the segment address of the base, and then do something
  406. X * like:
  407. X *         *MK_FP(baseseg, offset) = blahblah;
  408. X *
  409. X * whenever we need to access the table. This SHOULD be more efficient,
  410. X * but the compilers do not appear to generate very efficient code in this
  411. X * case. Huge pointers are not used, because they are slow, and because
  412. X * Zortech does not support them.
  413. X */
  414. X
  415. X#ifdef MSC
  416. X#define farmalloc(n)    halloc(n, 1)
  417. X#endif
  418. X
  419. Xint taballoc()
  420. X{
  421. X    char far *X;
  422. X
  423. X    if (do_decomp) {
  424. X        if ((de_stack = malloc(DE_STACKLEN)) == 0)
  425. X            return (0);
  426. X    }
  427. X    else {
  428. X        if ((X = farmalloc((HSIZE + PARA) * sizeof(code_t))) == 0)
  429. X            return (0);
  430. X        codeptrs2[0] = MK_FP(FP_SEGCEIL(X), 0);
  431. X        codeptrs2[1] = MK_FP(FP_SEGCEIL(X) + HSIZE/PARA, 0);
  432. X    }
  433. X
  434. X    if ((X = farmalloc((HSIZE + PARA) * sizeof(char))) == 0)
  435. X        return (0);
  436. X    charptr1 = MK_FP(FP_SEGCEIL(X), 0);
  437. X
  438. X    if ((X = farmalloc((HSIZE + PARA) * sizeof(code_t))) == 0)
  439. X        return (0);
  440. X    codeptrs1[0] = MK_FP(FP_SEGCEIL(X), 0);
  441. X    codeptrs1[1] = MK_FP(FP_SEGCEIL(X) + HSIZE/PARA, 0);
  442. X
  443. X    return (1);
  444. X}
  445. X
  446. X#else
  447. X
  448. Xuchar    chartab1[HSIZE];
  449. Xcode_t    codetab1[HSIZE];
  450. Xcode_t    codetab2[HSIZE];
  451. X
  452. X#define de_suffixof(i)    chartab1[i]
  453. X#define de_prefixof(i)    codetab1[i]
  454. X#define de_stack    (uchar *)codetab2
  455. X
  456. X#define en_hashchar(i)    chartab1[i]
  457. X#define en_hashent(i)    codetab1[i]
  458. X#define en_hashcode(i)    codetab2[i]
  459. X
  460. X#endif
  461. X
  462. Xvoid Usage()
  463. X{
  464. X    fprintf(stderr, "Usage: compress [-dfvcVnC] [-b maxbits] [file ...]\n");
  465. X    fprintf(stderr, "    -V => print Version\n");
  466. X    fprintf(stderr, "    -d => decompress\n");
  467. X    fprintf(stderr, "    -v => verbose\n");
  468. X    fprintf(stderr, "    -f => force overwrite of output file\n");
  469. X    fprintf(stderr, "    -n => no header: useful to uncompress old files\n");
  470. X    fprintf(stderr, "    -b maxbits => maxbits. Default %d\n", BITS);
  471. X    fprintf(stderr, "    -c => cat all output to stdout\n");
  472. X    fprintf(stderr, "    -C => generate output compatible with compress 2.0.\n");
  473. X}
  474. X
  475. X/*****************************************************************
  476. X * TAG( main )
  477. X *
  478. X * Algorithm from "A Technique for High Performance Data Compression",
  479. X * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
  480. X *
  481. X * Usage: compress [-dfvc] [-b bits] [file ...]
  482. X * Inputs:
  483. X *    -d:        If given, decompression is done instead.
  484. X *
  485. X *      -c:         Write output on stdout, don't remove original.
  486. X *
  487. X *      -b:         Parameter limits the max number of bits/code.
  488. X *
  489. X *    -f:        Forces output file to be generated, even if one already
  490. X *            exists, and even if no space is saved by compressing.
  491. X *            If -f is not used, the user will be prompted if stdin is
  492. X *            a tty, otherwise, the output file will not be overwritten.
  493. X *
  494. X *      -v:        Write compression statistics
  495. X *
  496. X *     file ...:   Files to be compressed.  If none specified, stdin
  497. X *            is used.
  498. X * Outputs:
  499. X *    file.Z:        Compressed form of file with same mode, owner, and utimes
  500. X *     or stdout   (if stdin used as input)
  501. X *
  502. X * Assumptions:
  503. X *    When filenames are given, replaces with the compressed version
  504. X *    (.Z suffix) only if the file decreases in size.
  505. X * Algorithm:
  506. X *     Modified Lempel-Ziv method (LZW).  Basically finds common
  507. X * substrings and replaces them with a variable size code.  This is
  508. X * deterministic, and can be done on the fly.  Thus, the decompression
  509. X * procedure needs no input table, but tracks the way the table was built.
  510. X */
  511. X
  512. X#ifdef __ZTC__
  513. X#include <int.h>
  514. Xint silly_nonsense(struct INT_DATA *foo) {raise(SIGINT); return 1;}
  515. X#endif
  516. X
  517. X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
  518. X
  519. Xvoid main(argc, argv)
  520. Xint argc;
  521. Xchar **argv;
  522. X{
  523. X    char tempname[100], *cp;
  524. X
  525. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
  526. X        signal(SIGINT, onintr);
  527. X#ifdef __ZTC__
  528. X        /*
  529. X         * The "signal" call above isn't good enough for Zortech
  530. X         */
  531. X        int_intercept(0x23, silly_nonsense, 256);
  532. X#endif
  533. X#ifdef SIGSEGV
  534. X        signal(SIGSEGV, oops);
  535. X#endif
  536. X        if (isatty(2))
  537. X            foreground = 1;
  538. X    }
  539. X
  540. X#ifndef MSDOS
  541. X    if ((cp = strrchr(argv[0], '/')) != 0)
  542. X        cp++;
  543. X    else
  544. X        cp = argv[0];
  545. X#else
  546. X    for (cp = argv[0]; *cp; cp++)
  547. X        if (*cp == '/' || *cp == '\\')
  548. X            argv[0] = cp + 1;
  549. X    cp = strlwr(argv[0]);
  550. X#endif
  551. X    /* Limited to 8 char filenames under DOS */
  552. X    if (strncmp(cp, "uncompress", 8) == 0)
  553. X        do_decomp = 1;
  554. X    else if (strncmp(cp, "zcat", 4) == 0) {
  555. X        do_decomp = 1;
  556. X        zcat_flg = 1;
  557. X    }
  558. X
  559. X#ifdef BSD4_2
  560. X    /* 4.2BSD dependent - take it out if not */
  561. X    setlinebuf(stderr);
  562. X#endif /* BSD4_2 */
  563. X
  564. X    for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
  565. X        while (*++(*argv)) {    /* Process all flags in this arg */
  566. X            switch (**argv) {
  567. X            case 'V':
  568. X                version();
  569. X                break;
  570. X            case 'v':
  571. X                verbose = 1;
  572. X                break;
  573. X            case 'd':
  574. X                do_decomp = 1;
  575. X                break;
  576. X            case 'f':
  577. X            case 'F':
  578. X                force = 1;
  579. X                break;
  580. X            case 'n':
  581. X                magic = 0;
  582. X                break;
  583. X            case 'C':
  584. X                block_compress = 0;
  585. X                break;
  586. X            case 'b':
  587. X                if (!ARGVAL()) {
  588. X                    fprintf(stderr, "Missing maxbits\n");
  589. X                    Usage();
  590. X                    exit(1);
  591. X                }
  592. X                maxbits = atoi(*argv);
  593. X                goto nextarg;
  594. X            case 'c':
  595. X                zcat_flg = 1;
  596. X                break;
  597. X            case 'q':
  598. X                verbose = 0;
  599. X                break;
  600. X            default:
  601. X                fprintf(stderr, "Unknown flag: '%c'; ", **argv);
  602. X                Usage();
  603. X                exit(1);
  604. X            }
  605. X        }
  606. Xnextarg:;
  607. X    }
  608. X
  609. X#ifdef i8088
  610. X    if (! taballoc()) {
  611. X        fprintf(stderr, "compress: out of memory\n");
  612. X        exit(1);
  613. X    }
  614. X#endif
  615. X    /*
  616. X     * If no filename args, do standard input.
  617. X     */
  618. X    if (argc <= 0) {
  619. X        if (! ifopen((char *)0) || ! ofopen((char *)0))
  620. X            exit(1);
  621. X
  622. X        ifname = "stdin";
  623. X
  624. X        if (do_decomp) {
  625. X            if (!check_magic())
  626. X                exit(1);
  627. X            decompress();
  628. X        }
  629. X        else {
  630. X            compress();
  631. X            if (verbose)
  632. X                putc('\n', stderr);
  633. X        }
  634. X        exit(exit_stat);
  635. X    }
  636. X
  637. X    while (--argc >= 0) {
  638. X        char *suf;
  639. X
  640. X        ifname = *argv++;
  641. X        suf = strrchr(ifname, '.');
  642. X
  643. X        exit_stat = 0;
  644. X        okunlink = 0;
  645. X
  646. X        if (do_decomp) {        /* DECOMPRESSION */
  647. X            if (!suf || (strcmp(suf, ".Z") && strcmp(suf, ".z"))) {
  648. X                strcpy(tempname, ifname);
  649. X                strcat(tempname, ".Z");
  650. X                ifname = tempname;
  651. X            }
  652. X            if (! ifopen(ifname) || !check_magic())
  653. X                continue;
  654. X            if (zcat_flg)
  655. X                ofname[0] = '\0';
  656. X            else {
  657. X                strcpy(ofname, ifname);
  658. X                ofname[strlen(ifname) - 2] = '\0';
  659. X            }
  660. X            if (!ofopen(ofname))
  661. X                continue;
  662. X            if (!zcat_flg && verbose)
  663. X                fprintf(stderr, "%s: ", ifname);
  664. X            decompress();
  665. X        }
  666. X        else {                /* COMPRESSION */
  667. X            if (suf && (!strcmp(suf, ".Z") || !strcmp(suf, ".z"))) {
  668. X                fprintf(stderr, "%s: already has .Z suffix -- no change\n",
  669. X                    ifname);
  670. X                continue;
  671. X            }
  672. X            if (! ifopen(ifname))
  673. X                continue;
  674. X            if (zcat_flg)
  675. X                ofname[0] = 0;
  676. X            else {
  677. X                strcpy(ofname, ifname);
  678. X#ifndef MSDOS    /* We'll let ofopen do the complaining */
  679. X#ifndef BSD4_2
  680. X                if ((cp = strrchr(ofname, '/')) != NULL)
  681. X                    cp++;
  682. X                else
  683. X                    cp = ofname;
  684. X                if (strlen(cp) > 12) {
  685. X                    fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
  686. X                    continue;
  687. X                }
  688. X#endif
  689. X#endif
  690. X                strcat(ofname, ".Z");
  691. X            }
  692. X            if (! ofopen(ofname))
  693. X                continue;
  694. X            if (! zcat_flg && verbose)
  695. X                fprintf(stderr, "%s: ", ifname);
  696. X            compress();
  697. X        }
  698. X
  699. X        if (! zcat_flg) {
  700. X            copystat();
  701. X            if ((exit_stat == 1) || verbose)
  702. X                putc('\n', stderr);
  703. X        }
  704. X    }
  705. X    exit(exit_stat);
  706. X}
  707. X
  708. X/*
  709. X * compress stdin to stdout
  710. X *
  711. X * Algorithm:  use open addressing double hashing (no chaining) on the 
  712. X * prefix code / next character combination.  We do a variant of Knuth's
  713. X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  714. X * secondary probe.  Here, the modular division first probe is gives way
  715. X * to a faster exclusive-or manipulation.  Also do block compression with
  716. X * an adaptive reset, whereby the code table is cleared when the compression
  717. X * ratio decreases, but after the table fills.  The variable-length output
  718. X * codes are re-sized at this point, and a special CLEAR code is generated
  719. X * for the decompressor.  Late addition:  construct the table according to
  720. X * file size for noticeable speed improvement on small files.  Please direct
  721. X * questions about this implementation to ames!jaw.
  722. X *
  723. X * Secondary hash function changed slightly for DOS. Hash table used to be
  724. X * > 64K. This is slow on a 16 bit machine because it means long arithmetic,
  725. X * and more complicated addressing of tables in the far address space.
  726. X * We now restrict the table size to 64K, and, so that the table does
  727. X * not overfill, restrict the codes that we will generate to MAXMAXCODE.
  728. X * This causes slightly poorer compression in some cases, but, interestingly
  729. X * enough, also causes better compression ratios in certain other cases.
  730. X * Yes, this is all compatible with other compresses.
  731. X */
  732. Xstatic long    in_count;        /* length of input */
  733. Xstatic long    out_count;        /* length of compressed output */
  734. Xstatic long    ratio;            /* in_count/out_count * 256 */
  735. Xstatic int    n_bits;            /* number of bits/code */
  736. Xstatic int    n_bits8;        /* bits/code times 8 */
  737. Xstatic int    bitoffset;        /* Offset into bitbuf */
  738. X
  739. X#define NOENT        ((code_t)0xffff)
  740. X#define MAXMAXCODE    ((code_t)0xf000)
  741. X
  742. X/*
  743. X * Clear out the hash table. We try to do this as quickly as possible, because
  744. X * it's running time dominates for small files. For big files, it doesn't matter
  745. X * much because it doesn't get called often. Now I understand why the original
  746. X * had a variable size hash table.
  747. X */
  748. Xvoid clearhash()
  749. X{
  750. X#ifdef i8088
  751. X    register unsigned i;
  752. X    code_t far *hp;
  753. X
  754. X    hp = (code_t far *)codeptrs1[0];
  755. X    i = (unsigned)(HSIZE/2);
  756. X    do
  757. X        *hp++ = NOENT;
  758. X    while (--i > 0);
  759. X
  760. X    hp = (code_t far *)codeptrs1[1];
  761. X    i = (unsigned)(HSIZE/2);
  762. X    do
  763. X        *hp++ = NOENT;
  764. X    while (--i > 0);
  765. X#else
  766. X    /*
  767. X     * WARNING: assumes that NOENT == 0xffff
  768. X     */
  769. X    memset((char *)codetab1, 0xff, HSIZE*sizeof(code_t));
  770. X#endif
  771. X}
  772. X
  773. X/*
  774. X * Compress stdin to stdout.
  775. X */
  776. Xvoid compress()
  777. X{
  778. X    register hash_t    i;
  779. X    register code_t    ent;
  780. X    hash_t        disp;
  781. X    int        c;
  782. X    code_t        freecode;    /* first unused entry */
  783. X    code_t        maxcode;    /* maximum code, given n_bits */
  784. X    code_t        maxmaxcode;
  785. X    code_t        k;
  786. X#ifdef CHECK_GAP
  787. X    long        checkpoint = 0;
  788. X#endif
  789. X
  790. X    if (maxbits < INIT_BITS)
  791. X        maxbits = INIT_BITS;
  792. X    if (maxbits > BITS)
  793. X        maxbits = BITS;
  794. X
  795. X    if (magic) {
  796. X        putchar(MAGIC0); putchar(MAGIC1);
  797. X        putchar(maxbits | block_compress);
  798. X        if (ferror(stdout))
  799. X            writeerr();
  800. X    }
  801. X
  802. X    bitbuf[bitoffset = 0] = 0;
  803. X    out_count = 3;            /* includes 3-byte header mojo */
  804. X    ratio = 0;
  805. X    in_count = 1;
  806. X
  807. X    n_bits = INIT_BITS;
  808. X    n_bits8 = INIT_BITS << 3;
  809. X    maxcode = MAXCODE(INIT_BITS);
  810. X    maxmaxcode = MAXCODE(maxbits);
  811. X    if (maxmaxcode > MAXMAXCODE)
  812. X        maxmaxcode = MAXMAXCODE;
  813. X
  814. X    freecode = ((block_compress) ? FIRST : 256);
  815. X
  816. X    clearhash();
  817. X
  818. X    ent = getchar();
  819. X
  820. X    while ((c = getchar()) != EOF) {
  821. X        in_count++;
  822. X
  823. X        i = (hash_t)(c << 8) ^ ent;        /* xor hashing */
  824. X
  825. X        if ((k = en_hashent(i)) == ent && en_hashchar(i) == (uchar)c) {
  826. X            ent = en_hashcode(i);
  827. X            goto Continue;
  828. X        }
  829. X
  830. X        if (k != NOENT) {
  831. X            /*
  832. X             * New secondary hash for 64K table.
  833. X             * Experiment shows that the shift by 6 works well.
  834. X             * Beats me why. "disp" must be relatively
  835. X             * prime to the table size. Since the table size is a
  836. X             * power of 2, this means "disp" must be odd.
  837. X             *
  838. X             * Note that we do not do a range check before doing
  839. X             * "i -= disp". It is assumed that the hash table size
  840. X             * (HSIZE) is 64K, and that the type "hash_t" (which
  841. X             * is unsigned short) is 16 bits. Thus it is impossible
  842. X             * for "i" to be out of range. On a machine with something
  843. X             * other than 16 bit shorts, this would have to change.
  844. X             */
  845. X            disp = ((hash_t)(c << 6) ^ ent) | 1;
  846. X            do {
  847. X                i -= disp;
  848. X                if ((k = en_hashent(i)) == ent &&
  849. X                    en_hashchar(i) == (uchar)c) {
  850. X                    ent = en_hashcode(i);
  851. X                    goto Continue;
  852. X                }
  853. X            } while (k != NOENT);
  854. X        }
  855. X
  856. X        putcode(ent);
  857. X
  858. X        if (freecode <= maxmaxcode) {
  859. X            /*
  860. X             * Add the new entry.
  861. X             */
  862. X            en_hashchar(i) = (uchar)c;
  863. X            en_hashent(i) = ent;
  864. X            en_hashcode(i) = freecode;
  865. X
  866. X            /*
  867. X             * If the next entry is going to be too big for the
  868. X             * code size, then increase it, if possible.
  869. X             */
  870. X            if (freecode++ > maxcode) {
  871. X                while (bitoffset)
  872. X                    putcode(0);
  873. X                ++n_bits;
  874. X                n_bits8 += 8;
  875. X                maxcode = MAXCODE(n_bits);
  876. X            }
  877. X        }
  878. X#ifdef CHECK_GAP
  879. X        else if (in_count >= checkpoint && block_compress) {
  880. X            checkpoint = in_count + CHECK_GAP;
  881. X            if (need_clear()) {
  882. X#else
  883. X        else if (block_compress) {
  884. X            if (1) {
  885. X#endif
  886. X                putcode(CLEAR);
  887. X                while (bitoffset > 0)
  888. X                    putcode(0);
  889. X                clearhash();
  890. X                freecode = FIRST;
  891. X                maxcode = MAXCODE(INIT_BITS);
  892. X                n_bits = INIT_BITS;
  893. X                n_bits8 = n_bits << 3;
  894. X            }
  895. X        }
  896. X        ent = c;
  897. XContinue:;
  898. X    }
  899. X    /*
  900. X     * Put out the final code.
  901. X     */
  902. X    putcode(ent);
  903. X
  904. X    /*
  905. X     * At EOF, write the rest of the buffer.
  906. X     */
  907. X    if (bitoffset > 0)
  908. X        fwrite(bitbuf, 1, (bitoffset + 7) / 8, stdout);
  909. X    out_count += (bitoffset + 7) / 8;
  910. X    fflush(stdout);
  911. X    if (ferror(stdout))
  912. X        writeerr();
  913. X
  914. X    /*
  915. X     * Print out stats on stderr
  916. X     */
  917. X    if (! zcat_flg && verbose) {
  918. X        fprintf(stderr, "Compression: ");
  919. X        prratio(in_count - out_count, in_count);
  920. X    }
  921. X    if (out_count > in_count)    /* exit(2) if no savings */
  922. X        exit_stat = 2;
  923. X}
  924. X
  925. X/*
  926. X * Output the given code. Assumes that chars are 8 bits.
  927. X * "n_bits" output bytes (containing 8 codes) are assembled
  928. X * in in "bitbuf", and then written out.
  929. X */
  930. Xvoid putcode(code)
  931. Xcode_t code;
  932. X{
  933. X    register int i;
  934. X    register uchar *bp;
  935. X
  936. X    bp = &bitbuf[(bitoffset >> 3)];
  937. X    i = bitoffset & 7;
  938. X    bp[0] |= (uchar)(code << i);
  939. X    bp[1] = (uchar)(code >>= (8 - i));
  940. X    bp[2] = (uchar)(code >> 8);
  941. X
  942. X    if ((bitoffset += n_bits) == n_bits8) {
  943. X        bp = bitbuf;
  944. X        i = n_bits;
  945. X        out_count += i;
  946. X        do
  947. X            putchar(*bp++);
  948. X        while (--i);
  949. X        bitbuf[bitoffset = 0] = 0;
  950. X    }
  951. X}
  952. X
  953. X#ifdef CHECK_GAP
  954. X/*
  955. X * Compute the current compression ratio, and return non-zero if
  956. X * it is has decreased since the last we checked.
  957. X *
  958. X * Don't use this anymore. Whenever the hash table fills,
  959. X * we send a CLEAR immediately (if block_compress). This is faster,
  960. X * and doesn't appear to affect the compression ratio much.
  961. X */
  962. Xint need_clear()
  963. X{
  964. X    long rat;
  965. X
  966. X    if (in_count > 0x007fffffL) {        /* shift will overflow */
  967. X        rat = out_count >> 8;
  968. X        if (rat == 0)                 /* Don't divide by zero */
  969. X            rat = 0x7fffffffL;
  970. X        else
  971. X            rat = in_count / rat;
  972. X    } else
  973. X        rat = (in_count << 8) / out_count;
  974. X
  975. X    if (rat > ratio) {
  976. X        ratio = rat;
  977. X        return (0);
  978. X    }
  979. X    else {
  980. X        ratio = 0;
  981. X        return (1);
  982. X    }
  983. X}
  984. X#endif
  985. X
  986. X/*
  987. X * Decompress stdin to stdout. This code assumes that chars are 8 bits.
  988. X */
  989. Xvoid decompress()
  990. X{
  991. X    register uchar    *stackp;
  992. X    register code_t    code;
  993. X    code_t        oldcode, incode;
  994. X    code_t        codemask;
  995. X    code_t        freecode;        /* first unused entry */
  996. X    code_t        maxcode;        /* maximum code, given n_bits */
  997. X    code_t        maxmaxcode;
  998. X    int        finchar;
  999. X    int        size;            /* #bits in bitbuf */
  1000. X    int        bitoff;            /* Offset into bitbuf */
  1001. X    int        n_bits;            /* number of bits/code */
  1002. X#ifndef i8088
  1003. X    register uchar    *bp;
  1004. X#endif
  1005. X
  1006. X    n_bits = INIT_BITS;
  1007. X    maxcode = MAXCODE(INIT_BITS) - 1;
  1008. X    codemask = MAXCODE(INIT_BITS);
  1009. X    freecode = ((block_compress) ? FIRST : 256) - 1;
  1010. X    maxmaxcode = MAXCODE(maxbits);
  1011. X
  1012. X    /*
  1013. X     * Read the first code into "oldcode"
  1014. X     */
  1015. X    if ((size = fread(bitbuf, 1, n_bits, stdin)) <= 0)
  1016. X        return;
  1017. X    size = (size << 3) - (n_bits - 1);
  1018. X    oldcode = (bitbuf[0] | (bitbuf[1] << 8)) & codemask;
  1019. X    bitoff = n_bits;
  1020. X
  1021. X    /*
  1022. X     * First code must be 8 bits == char. Write it, and die
  1023. X     * if it can't be written.
  1024. X     */
  1025. X    putchar(finchar = oldcode);
  1026. X    if (ferror(stdout))
  1027. X        writeerr();
  1028. X
  1029. X    stackp = de_stack;
  1030. X
  1031. X    for ( ; ; ) {
  1032. X        if (bitoff >= size) {
  1033. X            if ((size = fread(bitbuf, 1, n_bits, stdin)) <= 0)
  1034. X                break;
  1035. X            /* Round size down to integral number of codes */
  1036. X            size = (size << 3) - (n_bits - 1);
  1037. X            bitoff = 0;
  1038. X        }
  1039. X        /*
  1040. X         * Read the next code into "code". On the 8088,
  1041. X         * a slight speedup is possible because it has the right byte
  1042. X         * order, and no alignment restrictions.
  1043. X         */
  1044. X#ifdef i8088
  1045. X        code = ((code_t)(*(long *)&bitbuf[(bitoff >> 3)] >>
  1046. X             (bitoff&7))) & codemask;
  1047. X#else
  1048. X        bp = &bitbuf[(bitoff >> 3)];
  1049. X        code = (code_t)(((bp[0] | (code_t)bp[1] << 8) |
  1050. X             (ulong)bp[2] << 16) >> (bitoff & 7)) & codemask;
  1051. X#endif
  1052. X        bitoff += n_bits;
  1053. X
  1054. X        if ((code == CLEAR) && block_compress) {
  1055. X            n_bits = INIT_BITS;
  1056. X                maxcode = MAXCODE(INIT_BITS) - 1;
  1057. X            codemask = MAXCODE(INIT_BITS);
  1058. X            freecode = (FIRST - 1) - 1;
  1059. X            size = 0;
  1060. X            continue;
  1061. X        }
  1062. X        incode = code;
  1063. X
  1064. X        /*
  1065. X         * Special case for KwKwK string.
  1066. X         */
  1067. X        if (code > freecode) {
  1068. X            if (code != freecode + 1)
  1069. X                oops();
  1070. X                *stackp++ = (uchar)finchar;
  1071. X            code = oldcode;
  1072. X        }
  1073. X
  1074. X        /*
  1075. X         * Generate output characters in reverse order
  1076. X         */
  1077. X        while (code >= 256) {
  1078. X            *stackp++ = de_suffixof(code);
  1079. X            code = de_prefixof(code);
  1080. X        }
  1081. X
  1082. X        /*
  1083. X         * And write them out in the forward order.
  1084. X         */
  1085. X        putchar(finchar = code);
  1086. X        for (code = (stackp - de_stack) + 1; --code != 0; )
  1087. X            putchar(*--stackp);
  1088. X
  1089. X        /*
  1090. X         * Generate the new entry.
  1091. X         */
  1092. X        if (freecode < maxmaxcode) {
  1093. X            if (++freecode > maxcode) {
  1094. X                if (++n_bits == maxbits)
  1095. X                    maxcode = maxmaxcode;
  1096. X                else
  1097. X                    maxcode = MAXCODE(n_bits) - 1;
  1098. X                size = 0;
  1099. X                codemask = MAXCODE(n_bits);
  1100. X            }
  1101. X            de_prefixof(freecode) = oldcode;
  1102. X            de_suffixof(freecode) = (uchar)finchar;
  1103. X        } 
  1104. X        /*
  1105. X         * Remember previous code.
  1106. X         */
  1107. X        oldcode = incode;
  1108. X    }
  1109. X    fflush(stdout);
  1110. X    if (ferror(stdout))
  1111. X        writeerr();
  1112. X}
  1113. X
  1114. X/*
  1115. X * Check a compressed file to make sure it has the proper magic number
  1116. X * at the beginning. Also read the third byte to determine "maxbits",
  1117. X * and "block_compress".
  1118. X */
  1119. Xint check_magic()
  1120. X{
  1121. X    if (! magic)
  1122. X        return (1);
  1123. X    if ((getchar() != MAGIC0) || (getchar() != MAGIC1)) {
  1124. X        fprintf(stderr, "%s: not in compressed format\n", ifname);
  1125. X        return (0);
  1126. X    }
  1127. X    maxbits = getchar();    /* set -b from file */
  1128. X    block_compress = maxbits & BLOCK_MASK;
  1129. X    maxbits &= BIT_MASK;
  1130. X    if (maxbits > BITS) {
  1131. X        fprintf(stderr,
  1132. X           "%s: compressed with %d bits, can only handle %d bits\n",
  1133. X            ifname, maxbits, BITS);
  1134. X        return (0);
  1135. X    }
  1136. X    return (1);
  1137. X}
  1138. X
  1139. Xvoid writeerr()
  1140. X{
  1141. X    perror(ofname);
  1142. X    fclose(stdout);
  1143. X    unlink(ofname);
  1144. X    exit(1);
  1145. X}
  1146. X
  1147. X/*
  1148. X * Copy the permissions and file times from the input file to the
  1149. X * output.
  1150. X */
  1151. Xvoid copystat()
  1152. X{
  1153. X    struct stat statbuf;
  1154. X    int mode;
  1155. X    void (* ss)();
  1156. X#ifndef __TURBOC__
  1157. X    time_t timep[2];
  1158. X#else
  1159. X    struct ftime filetime;
  1160. X    int fd;
  1161. X#endif
  1162. X
  1163. X    fclose(stdout);
  1164. X    if (stat(ifname, &statbuf)) {        /* Get stat on input file */
  1165. X        perror(ifname);
  1166. X        return;
  1167. X    }
  1168. X    if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
  1169. X        if (! verbose)
  1170. X                fprintf(stderr, "%s: ", ifname);
  1171. X        fprintf(stderr, " -- not a regular file: unchanged");
  1172. X        exit_stat = 1;
  1173. X    }
  1174. X    else if (statbuf.st_nlink > 1) {
  1175. X        if (! verbose)
  1176. X            fprintf(stderr, "%s: ", ifname);
  1177. X        fprintf(stderr, " -- has %d other links: unchanged",
  1178. X            statbuf.st_nlink - 1);
  1179. X        exit_stat = 1;
  1180. X    }
  1181. X    else if (exit_stat == 2 && !force) { /* No compression: remove file.Z */
  1182. X        if (verbose)
  1183. X            fprintf(stderr, " -- file unchanged");
  1184. X    }
  1185. X    else {            /* ***** Successful Compression ***** */
  1186. X        exit_stat = 0;
  1187. X        mode = statbuf.st_mode & 07777;
  1188. X#ifndef __ZTC__
  1189. X        if (chmod(ofname, mode))        /* Copy modes */
  1190. X            perror(ofname);
  1191. X#endif
  1192. X#ifndef MSDOS
  1193. X        chown(ofname, statbuf.st_uid, statbuf.st_gid);    /* Copy ownership */
  1194. X#endif
  1195. X#ifndef __TURBOC__
  1196. X        timep[0] = statbuf.st_atime;
  1197. X        timep[1] = statbuf.st_mtime;
  1198. X        utime(ofname, timep);
  1199. X#else
  1200. X        if ((fd = open(ofname, O_RDONLY)) >= 0) {
  1201. X            if (getftime(fileno(stdin), &filetime) == 0)
  1202. X                setftime(fd, &filetime);
  1203. X            close(fd);
  1204. X        }
  1205. X#endif
  1206. X        fclose(stdin);
  1207. X        ss = signal(SIGINT, SIG_IGN);
  1208. X        okunlink = 0;
  1209. X        /* ^C here would leave both input, and output files around */
  1210. X        if (unlink(ifname))    /* Remove input file */
  1211. X            perror(ifname);
  1212. X        signal(SIGINT, ss);
  1213. X        if (verbose)
  1214. X            fprintf(stderr, " -- replaced with %s", ofname);
  1215. X        return;        /* Successful return */
  1216. X    }
  1217. X
  1218. X    /* Unsuccessful return -- one of the tests failed */
  1219. X
  1220. X    if (unlink(ofname))
  1221. X        perror(ofname);
  1222. X}
  1223. X
  1224. Xvoid onintr()
  1225. X{
  1226. X    fclose(stdout);
  1227. X    if (okunlink)
  1228. X        unlink(ofname);
  1229. X    exit(1);
  1230. X}
  1231. X
  1232. Xvoid oops()    /* wild pointer -- assume bad input */
  1233. X{
  1234. X    if (do_decomp) 
  1235. X        fprintf (stderr, "uncompress: %s is corrupt.\n", ifname);
  1236. X    fclose(stdout);
  1237. X    if (okunlink)
  1238. X        unlink(ofname);
  1239. X    exit(1);
  1240. X}
  1241. X
  1242. Xvoid prratio(num, den)
  1243. Xlong int num, den;
  1244. X{
  1245. X    register int q;                /* Doesn't need to be long */
  1246. X
  1247. X    if (num > 214748L)            /* 2147483647/10000 */
  1248. X        q = (int)(num / (den / 10000L));
  1249. X    else
  1250. X        q = (int)(10000L * num / den);    /* Long calculations, though */
  1251. X    if (q < 0) {
  1252. X        putc('-', stderr);
  1253. X        q = -q;
  1254. X    }
  1255. X    fprintf(stderr, "%d.%02d%%", q / 100, q % 100);
  1256. X}
  1257. X
  1258. Xvoid version()
  1259. X{
  1260. X    fprintf(stderr, "%s\n", rcs_ident);
  1261. X    fprintf(stderr, "BITS = %d\n", BITS);
  1262. X}
  1263. X
  1264. X/*
  1265. X * Open the file "ofname" for binary output with possible check
  1266. X * for overwrite. If all goes well, return non-zero, else zero.
  1267. X */
  1268. Xint ofopen(filename)
  1269. Xchar *filename;
  1270. X{
  1271. X    static char IOoutbuf[8192];
  1272. X    struct stat statbuf;
  1273. X
  1274. X    if (filename && !*filename)
  1275. X        filename = 0;
  1276. X
  1277. X    /*
  1278. X     * Check for overwrite of existing file
  1279. X     */
  1280. X    if (filename && !force && stat(filename, &statbuf) == 0) {
  1281. X        char response[2];
  1282. X        response[0] = 'n';
  1283. X        fprintf(stderr, "%s already exists;", filename);
  1284. X        if (foreground) {
  1285. X            fprintf(stderr, " do you wish to overwrite %s (y or n)? ", filename);
  1286. X            fflush(stderr);
  1287. X            read(2, response, 2);
  1288. X            while (response[1] != '\n') {
  1289. X                if (read(2, response+1, 1) < 0)    { /* Ack! */
  1290. X                    perror("stderr");
  1291. X                    break;
  1292. X                }
  1293. X            }
  1294. X        }
  1295. X        if (response[0] != 'y') {
  1296. X            fprintf(stderr, "\tnot overwritten\n");
  1297. X            return (0);
  1298. X        }
  1299. X    }
  1300. X
  1301. X    okunlink = 1;
  1302. X    /*
  1303. X     * Open the output file.
  1304. X     */
  1305. X    if (filename && !freopen(filename, "wb", stdout)) {
  1306. X        perror(filename);
  1307. X        return (0);
  1308. X    }
  1309. X#ifdef O_BINARY
  1310. X    setmode(fileno(stdout), O_BINARY);
  1311. X#else
  1312. X#ifdef __ZTC__
  1313. X    /*
  1314. X     * I'm sure there must be a better way in Zortech C to change the
  1315. X     * mode of an already opened file, but I can't find it. It doesn't
  1316. X     * have a "setmode" call it seems.
  1317. X     */
  1318. X    stdout->_flag &= ~_IOTRAN;
  1319. X#endif
  1320. X#endif
  1321. X    setvbuf(stdout, IOoutbuf, _IOFBF, sizeof(IOoutbuf));
  1322. X    return (1);
  1323. X}
  1324. X
  1325. Xifopen(filename)
  1326. Xchar *filename;
  1327. X{
  1328. X    static char IOinbuf[8192];
  1329. X
  1330. X    if (filename && !freopen(filename, "rb", stdin)) {
  1331. X        perror(filename);
  1332. X        return (0);
  1333. X    }
  1334. X#ifdef O_BINARY
  1335. X    setmode(fileno(stdin), O_BINARY);
  1336. X#else
  1337. X#ifdef __ZTC__
  1338. X    stdin->_flag &= ~_IOTRAN;
  1339. X#endif
  1340. X#endif
  1341. X    setvbuf(stdin, IOinbuf, _IOFBF, sizeof(IOinbuf));
  1342. X    return (1);
  1343. X}
  1344. END_OF_FILE
  1345. if test 32700 -ne `wc -c <'compress.c'`; then
  1346.     echo shar: \"'compress.c'\" unpacked with wrong size!
  1347. fi
  1348. # end of 'compress.c'
  1349. fi
  1350. echo shar: End of shell archive.
  1351. exit 0
  1352.  
  1353.